home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-17 / herkules.zip / HERKULES.ASM < prev    next >
Assembly Source File  |  1991-08-22  |  64KB  |  1,274 lines

  1. ;                         Assemble as COM-File!!!
  2. ;Dieses Programm hängt sich als Treiber in den INT10 ein und übernimmt Aufrufe
  3. ;in den VideoModes 7 und 8. Letzterer ist der von diesem Programm neu unter-
  4. ;stützte Herkules GraphikMode mit 720x360 Punkten. Der Vorteil von diesem Pro-
  5. ;gramm liegt darin, daß z.B. MSDOS nun auch im Herkules-GraphMode die Zeichen
  6. ;richtig darstellt. Leider müssen im GraphikMode beim Scrollen 32kB verschoben
  7. ;werden, was die Sache deutlich bremst. Um das zu umgehen, versucht das Pro-
  8. ;gramm, solche aufwendigen Scrolls durch Verschieben der DisplayStart-Adresse
  9. ;zu Beschleunigen. Ein Beispiel: Wenn der ganze Screen um eine Zeile nach oben
  10. ;geschoben werden soll, so muß man dazu 32670 Bytes bewegen. Setzt man aber
  11. ;die DisplayStart-Adresse des 6845 um 90 Bytes weiter, so hat das den
  12. ;gleichen Effekt wie das Scrollen, ist aber bedeutent schneller. Aber:
  13. ;Wenn man nur einen Teil des Screens verschieben will, so wird beim Umpro-
  14. ;grammieren des 6845 der Rest mitverschoben. Letzter muß daher vorher in die
  15. ;umgekehrte Richtung gescrolled werden, nach dem Ändern des DispStart ist
  16. ;er dann wieder an der richtigen Stelle. Beispiel:
  17. ;       ╔═════╤═════════════════════════════╤═════╗
  18. ;       ║     │              3              │     ║
  19. ;       ║     ╔═════════════════════════════╗     ║
  20. ;       ║     ║                             ║     ║
  21. ;       ║     ║                             ║     ║
  22. ;       ║     ║                             ║     ║
  23. ;       ║  2  ║              1              ║  4  ║
  24. ;       ║     ║                             ║     ║
  25. ;       ║     ║                             ║     ║
  26. ;       ║     ║                             ║     ║
  27. ;       ║     ╚═════════════════════════════╝     ║
  28. ;       ║     │              3              │     ║
  29. ;       ╚═════╧═════════════════════════════╧═════╝
  30. ;Soll Window 1 um eine Zeile nach oben gescrolled werden, so werden statt
  31. ;dessen nacheinander Bereiche 2, 3 und 4 (gehen über die vertikalen
  32. ;Bildschirmgrenzen herum!) um eine Zeile nach unten rotiert(!),
  33. ;und dann der DispStart um eine Zeile nach unten versetzt.
  34. ;Der Bildschirmspeicher der Herkules-Karte im Graphik-Modus ist in vier
  35. ;BitMaps unterteilt, die an den Adressen $B0000, $B2000, $B4000, $B6000
  36. ;beginnen, bzw in der zweiten Page $B8000, $BA000, $BC000 und $BE000.
  37. ;Aufeinanderfolgende Zeilen entstammen folgenden BitMaps:
  38. ;0 : BitMap 0  Zeile 0
  39. ;1 : BitMap 1  Zeile 0
  40. ;2 : BitMap 2  Zeile 0
  41. ;3 : BitMap 3  Zeile 0
  42. ;4 : BitMap 0  Zeile 1
  43. ;5 : BitMap 1  Zeile 1
  44. ;und so weiter. Vier aufeinanderfolgende Zeilen aus den BitMaps 0, 1, 2 und 3
  45. ;nennt man einen "Scan". Ein HiresZeichen aus dem 8x8-Font besteht somit aus
  46. ;2 Scans. Das Programm 'versteht' im Graphik-Modus nur zwei Attribut-Nibbles,
  47. ;von denen das High-Nibble für den Hintergrund und das Low-Nibble für das
  48. ;Zeichen zuständig sind. Sind die 3 LSBs eines Nibbles 0, so wird schwarz,
  49. ;in allen anderen Fällen weiß geschrieben.
  50. ;Zur Drucker-Ansteuerung bei Hardcopies müssen eventuell 6 Pascal-Strings
  51. ;angepasst werden, die sich im erzeugten COM-File nach dem Laden durch
  52. ;Debug an Offsets $110, $120, $130 etc befinden. Jeder String besteht aus
  53. ;einem LängenByte und maximal 15 Zeichen. Der erste wird am Beginn, der zweite
  54. ;am Ende einer TextScreen-HardCopy zum Drucker mit der Nummer, die an Offset
  55. ;$108 steht. Die nächsten zwei werden am Anfang sowie am Ende einer Graph-
  56. ;Screen-HardCopy gesendet, die letzten zwei am Anfang bzw am Ende jeder Zeile
  57. ;der Graphik-Hardcopy. Sie sollten den Drucker darüber informieren, daß jetzt
  58. ;720 Bytes 8Bit-Graphik kommen (wobei die 8 Bit SENKRECHT stehen!) bzw das
  59. ;Papier eine Zeile (bei Epson-Druckern also 8/72, nicht 1/6 Zoll) hoch-
  60. ;schieben.
  61. ;=============================================================================
  62. BsLineUp  EQU 0       ;Wenn der Cursor am Anfang der Zeile steht und dann ein
  63.                       ;CHR(8) kommt, soll der Cursor dann einfach dort stehen
  64.                       ;bleiben (0) oder auf das letzte Zeichen der vorherigen
  65.                       ;Zeile gesetzt werden (<>0) ?
  66. OptChar   EQU '/'
  67. False     EQU 0
  68. True      EQU NOT False
  69. Dunnow    EQU 01010101b                            ;(weder False noch True...)
  70. Ret_Ok    EQU 0
  71. Ret_Expl  EQU 1
  72. Ret_Error EQU 2
  73. NrOfDotsX EQU 720
  74. NrOfDotsY EQU 360
  75. ScrSize   EQU NrOfDotsX/8*NrOfDotsY
  76. NrOfChars EQU NrOfDotsX/8                             ;Im GraphikMode wird ein
  77. NrOfLines EQU NrOfDotsY/8                            ;8x8-Zeichensatz benutzt.
  78. WholeScr  EQU NrOfChars*NrOfLines
  79. BufSize   EQU WholeScr*2/2        ;Zum Rotieren wird im GraphikMode ein Buffer
  80.               ;benötigt. Da jede der 4 Pages einzeln rotiert wird, braucht man
  81.             ;pro Zeichen keine 8 sondern nur 2 Bytes. Außerdem wird um maximal
  82.             ;die halbe Bildschirm-Höhe rotiert, sonst würde andersrum rotiert.
  83. StackSize EQU 2*(24+24)    ;24 Worte für mich und 24 für sonstige Irq Routine.
  84. Page0Seg  EQU 0B000h
  85. Page1Seg  EQU 0B800h
  86. HGC_Diag  EQU 00b
  87. HGC_Text  EQU 10b
  88. HGC_Full  EQU 11b
  89. IndexReg  EQU 3B4h
  90. DataReg   EQU IndexReg+1
  91. ModeReg   EQU 3B8h
  92. StatusReg EQU 3BAh
  93. ConfigReg EQU 3BFh
  94. ;=============================================================================
  95. ;Hinter "IndexReg" und "DataReg" verbergen sich 16 Register des 6845. Um auf
  96. ;eines zugreifen zu können, muß seine Nummer in das "IndexReg" geschrieben
  97. ;werden, dann kann das selektierte Register durch das "DataReg" gelesen oder
  98. ;beschrieben werden.
  99. ;Regs  0-3  : Timing innerhalb einer Zeile
  100. ;Regs  4-7  : Timing innerhalb des Bildes
  101. ;Regs  8-9  : Miscellanous (wie schreibt man das?)
  102. ;Regs 10-11 : CursorShape
  103. ;Regs 12-13 : DispStart-Adress (Hi und Lo)
  104. ;Regs 14-15 : CursorPos-Adress (Hi und Lo)
  105. ;ModeReg:     x x x x  x x x x
  106. ;    2nd Page ┘ │ │ │  │ │ │ └ ?
  107. ;             ? ┘ │ │  │ │ └ Hires
  108. ;    Blink enable ┘ │  │ └ ?
  109. ;                 ? ┘  └ Display Enable
  110. ;StatusReg:   x x x x  x x x x
  111. ;   Vert retr ┘ │ │ │  │ │ │ └ Horiz retr
  112. ;             ? ┘ │ │  │ │ └ ?
  113. ;               ? ┘ │  │ └ ?
  114. ;                 ? ┘  └ Cur Pixel
  115. ;ConfigReg:   x x x x  x x x x
  116. ;          ? ─┴─┴─┴─┴──┴─┘ │ └ Enable Graphic Mode
  117. ;                          └ Enable 2nd Page
  118. ;=============================================================================
  119.  
  120. BiosData SEGMENT AT 40h
  121.   ORG 49h
  122.   CurVideoMode DB ?
  123.   NrOfColumns  DW ?
  124.   BytesPerPage DW ?
  125.   CurDispStart DW ?
  126.   CursPosTable DW 8 DUP (?)
  127.   CurCursShape DW ?
  128.   ActivePage   DB ?
  129.   VidCtrlIoAdr DW ?
  130.   ModeRegCont  DB ?
  131.   ORG 78h
  132.   TimeOutTable DB 4 DUP (?)
  133.   ORG 84h
  134.   LastTextLine DB ?
  135. BiosData ENDS
  136.  
  137. TheProgram SEGMENT BYTE PUBLIC
  138. ASSUME CS:TheProgram,DS:BiosData,ES:NOTHING,SS:NOTHING
  139. ORG 100h
  140.  
  141. EntryPoint PROC NEAR
  142.   jmp Main
  143.   DB 13,'(c)Stressi',26
  144. EntryPoint ENDP
  145.  
  146. ORG 10Fh
  147. PrnInfo         LABEL BYTE     ;Ab hier stehen die Drucker-Daten für "PrtScr":
  148. PrinterNr       DB 0           ;Zuerst die Nummer des zu benutzenden Druckers,
  149. PrnTextInit     DB 2,13,10                 ;dann die Strings, die vor bzw nach
  150.                 DB 16-($-PrnTextInit) DUP(-1)
  151. PrnTextExit     DB 0                     ;einer Text-HardCopy gesendet werden,
  152.                 DB 16-($-PrnTextExit) DUP(-1)
  153. PrnGraphInit    DB 2,13,10                      ;die Strings, die vor bzw nach
  154.                 DB 16-($-PrnGraphInit) DUP(-1)
  155. PrnGraphExit    DB 2,10,10               ;einer Graph-HardCopy gesendet werden
  156.                 DB 16-($-PrnGraphExit) DUP(-1)
  157. PrnLineStart    DB 4,27,'L',LOW NrOfDotsX,HIGH NrOfDotsX   ;sowie die, die vor
  158.                 DB 16-($-PrnLineStart) DUP(-1)
  159. PrnLineEnd      DB 4,13,27,'J',24 ;bzw nach jeder Graph-Zeile gesendet werden.
  160.                 DB 16-($-PrnLineEnd) DUP(-1)
  161. PrnInfoSize     EQU $-OFFSET PrinterNr
  162.  
  163. ReadLightpen    EQU NotImplemented
  164. ColorPalette    EQU NotImplemented
  165. Reserved        EQU NotImplemented
  166. FuncTable       DW SetVideoMode,SetCursorShape,SetCursorPos,ReadCursorPos
  167.                 DW ReadLightpen,SelActivePage,ScrollUp,ScrollDown
  168.                 DW ReadAttrChar,WriteAttrChar,WriteCharOnly,ColorPalette
  169.                 DW WriteDot,ReadDot,TeletypeOut,GetVideoState,Reserved
  170.                 DW Reserved,Reserved,WriteString
  171. GraphModeTiming DB 54,45,47, 7,95,0,90,90,2, 3, 0, 0,0,0          ;14 Bytes...
  172. TextModeTiming  DB 97,80,82,15,25,6,25,25,2,13,11,12,0,0
  173. DispStartTable  DW ?,?                              ;ByteOfs für je eine Page,
  174. PageSegment     DW Page0Seg,Page1Seg              ;bezogen auf diese Segmente.
  175. FastScrollFlag  DB Dunnow
  176. PrtScrActive    DB False
  177. Int10Active     DB False
  178. SavedInt10Vec   DW ?,?
  179. SavedInt5Vec    DW ?,?
  180. SavedInt10Stack DW ?,?
  181. SavedInt5Stack  DW ?,?
  182. PrtScr8x8Buffer DB 8,8 DUP (?)        ;zur Konvertierung: In der BitMap liegen
  183.                       ;die Bits waagerecht, der Drucker braucht sie senkrecht.
  184.  
  185. GetPageArrayIndex MACRO ArrayBase,DestReg  ;ZF=PageNr.
  186.   LOCAL IsPage0
  187.   mov  DestReg,ArrayBase
  188.   jz   IsPage0
  189.   inc  DestReg
  190.   inc  DestReg
  191. IsPage0:
  192. ENDM
  193.  
  194. DisplayAdress_Text MACRO XPos,YPos
  195.   ;XPos und YPos dürfen weder AL noch AH sein !!!
  196.   mov  al,80
  197.   mul  YPos
  198.   add  al,XPos
  199.   adc  ah,0
  200. ENDM  ;AX = WordAdress im VideoRam.
  201.  
  202. DisplayAdress_Graph MACRO XPos,YPos  ;XPos in Chars, YPos in Scans.
  203.   ;XPos und YPos dürfen weder AL noch AH sein !!!
  204.   mov  al,90                                 ;Eine ScanLine ist 90 Bytes lang,
  205.   mul  YPos                                        ;ein Char ist 2 Scans hoch.
  206.   add  al,XPos
  207.   adc  ah,0
  208. ENDM  ;AX = ByteAdress im VideoRam.
  209.  
  210. ZeichenSatz8x8 LABEL BYTE
  211. INCLUDE Herkules.INC
  212.  
  213. NewInt10Handler PROC FAR
  214.   jmp  SHORT HandleInterrupt
  215.   DB 'Herkules V1.0   '   ;müssen 16 Zeichen sein (Konvention...)
  216. HandleInterrupt:
  217.   cmp  cs:Int10Active,True                   ;"Herkules" schon mal aufgerufen?
  218.   je   NotAvailable                           ;Wir haben aber nur EINEN Stack!
  219.   cmp  ah,19                                                   ;FunctionNr>19?
  220.   ja   NotAvailable                           ;Wird von uns nicht unterstützt.
  221.   push si
  222.   mov  cs:Int10Active,True                     ;Flag setzen, daß jetzt auf den
  223.   mov  cs:SavedInt10Stack,sp                ;internen Stack umgeschaltet wird:
  224.   mov  cs:SavedInt10Stack+2,ss
  225.   mov  si,cs                                        ;Alten StackPointer merken
  226.   mov  ss,si                                   ;und auf neuen Stack umschalten
  227.   mov  sp,OFFSET MyInt10Stack+StackSize        ;(SP auf das ENDE des Stacks!).
  228.   push ds
  229.   push ax
  230.   mov  si,BiosData                            ;DS auf das Bios-Segment setzen.
  231.   mov  ds,si
  232.   xchg al,ah
  233.   mov  si,ax                                                ;FunctionNr von AH
  234.   xchg al,ah                                                  ;nach SI und von
  235.   and  si,00FFh                                       ;Byte nach Word wandeln.
  236.   jz   ThatConcernsMe                              ;Function 0? => In Ordnung.
  237.   mov  ah,CurVideoMode
  238.   cmp  ah,7                                                 ;Mode 7 (HercText)
  239.   je   ThatConcernsMe
  240.   cmp  ah,8                                                ;oder 8 (HercGraf)?
  241.   jne  CallOldBios
  242. ThatConcernsMe:                                   ;Dann geht das uns etwas an:
  243.   sti                                                     ;Interrupts enablen,
  244.   shl  si,1
  245.   call cs:[FuncTable+si]                         ;Behandlungs-Routine aufrufen
  246.   pop  ax                                                ;mit AH=CurVideoMode.
  247.   pop  ds
  248.   mov  ss,cs:SavedInt10Stack+2
  249.   mov  sp,cs:SavedInt10Stack               ;Auf alten Stack zurückschalten und
  250.   mov  cs:Int10Active,False               ;entsprechendes Flag wieder löschen,
  251.   pop  si                                               ;Register restaurieren
  252.   iret                                                            ;und zurück.
  253. NotAvailable:
  254.   jmp  dword ptr cs:[SavedInt10Vec]
  255. CallOldBios:
  256.   call NotImplemented                        ;Subroutine kommt NICHT zurück...
  257. NewInt10Handler ENDP
  258.  
  259. SelActivePage PROC NEAR  ;AL=new PageNr
  260.   and  al,1                                         ;Es gibt nur zwei Pages...
  261.   mov  ActivePage,al                             ;PageNr im BiosSeg speichern.
  262.   GetPageArrayIndex 0,si
  263.   push dx                                     ;DX darf nicht verändert werden!
  264.   mov  dx,ModeReg
  265.   mov  al,ModeRegCont                    ;Inhalt des ModeReg aus BiosSeg lesen
  266.   and  al,7Fh                                     ;Bit für "2nd Page" löschen.
  267.   test ActivePage,1                      ;Ist es denn wirklich die erste Page?
  268.   jz   SetModeReg                                  ;Dann neuen Wert schreiben.
  269.   or   al,80h                         ;Sonst Bit für "2nd Page" vorher setzen.
  270. SetModeReg:
  271.   mov  ModeRegCont,al                     ;Neuen Wert a) ins BiosSeg schreiben
  272.   out  dx,al                                ;und b) an den VideoChip schicken.
  273.   pop  dx
  274.   mov  ax,[CursPosTable+si]
  275.   call UpdateCursorPos        ;CursorPos der neuen Page an VideoChip schicken,
  276.   mov  ax,cs:[DispStartTable+si]
  277.   jmp  UpdateDispStart                                ;ebenso ihren DispStart.
  278. SelActivePage ENDP  ;AX and SI destroyed.
  279.  
  280. SetCursorShape PROC NEAR  ;CH=CursorStart, CL=CursorEnd
  281.   push dx
  282.   mov  CurCursShape,cx               ;Neue "CursorShape" im BiosSeg eintragen.
  283.   mov  dx,IndexReg
  284.   mov  al,11
  285.   out  dx,al                                          ;RegisterNr ins IndexReg
  286.   inc  dx
  287.   mov  al,cl
  288.   out  dx,al                                             ;LowByte ins DataReg.
  289.   dec  dx
  290.   mov  al,10                                           ;HighByte: Zuerst RegNr
  291.   out  dx,al                                                     ;ins IndexReg
  292.   inc  dx
  293.   mov  al,ch                                           ;und dann das DatenByte
  294.   out  dx,al                                                     ;ins DataReg.
  295.   pop  dx
  296.   ret
  297. SetCursorShape ENDP  ;AX destroyed.
  298.  
  299. SetCursorPos PROC NEAR   ;BH=PageNr, (DL/DH)=new CursorPos,  AH=CurVideoMode
  300.   mov  al,bh
  301.   and  al,1                           ;Mehr als 2 Seiten gibt's sowieso nicht.
  302.   GetPageArrayIndex OFFSET(CursPosTable),si
  303.   mov  [si],dx                     ;Neue Cursor Position im BiosSeg eintragen.
  304.   cmp  al,ActivePage             ;Wurde die CursorPos der active Page geändert
  305.   jne  SetCursPosDone
  306.   cmp  ah,7                            ;und ist auch noch der Text-Mode aktiv?
  307.   jne  SetCursPosDone
  308.   mov  ax,dx                                       ;Dann muß die neue Position
  309.   call UpdateCursorPos                       ;auch dem 6845 mitgeteilt werden.
  310. SetCursPosDone:
  311.   ret
  312. SetCursorPos ENDP  ;AX and SI destroyed.
  313.  
  314. ReadCursorPos PROC NEAR  ;BH=PageNr
  315.   test bh,1
  316.   GetPageArrayIndex OFFSET(CursPosTable),si
  317.   mov  dx,[si]
  318.   mov  cx,CurCursShape
  319.   ret
  320. ReadCursorPos ENDP  ;SI destroyed, CX=CursorShape, DX=CursorPos.
  321.  
  322. ScrollUp PROC NEAR
  323.   ;AL=NrOfLines, (CH/CL)-(DH/DL), BH=NewAttribute, AH=CurVideoMode.
  324.   cmp  ch,LastTextLine
  325.   ja   InvalidWindow
  326.   cmp  dh,ch                                        ;LowerCorner<=UpperCorner?
  327.   jb   InvalidWindow                            ;Da tun wir am besten gar nix,
  328.   cmp  dl,cl                              ;ebenso bei RightCorner<=LeftCorner.
  329.   jb   InvalidWindow
  330.   push bx
  331.   mov  bl,bh
  332.   mov  bh,ActivePage
  333.   call ScrollPartOfScreenUp
  334.   pop  bx
  335. InvalidWindow:
  336.   ret
  337. ScrollUp ENDP  ;AX and SI destroyed.
  338.  
  339. ScrollDown PROC NEAR
  340.   ;AL=NrOfLines, (CH/CL)-(DH/DL), BH=NewAttribute, AH=CurVideoMode.
  341.   cmp  ch,LastTextLine
  342.   ja   InvalidWindow
  343.   cmp  dh,ch                                        ;LowerCorner<=UpperCorner?
  344.   jb   InvalidWindow                            ;Da tun wir am besten gar nix,
  345.   cmp  dl,cl                              ;ebenso bei RightCorner<=LeftCorner.
  346.   jb   InvalidWindow
  347.   push bx
  348.   mov  bl,bh
  349.   mov  bh,ActivePage
  350.   call ScrollPartOfScreenDown
  351.   pop  bx
  352.   ret
  353. ScrollDown ENDP
  354.  
  355. ReadAttrChar PROC NEAR  ;BH=PageNr, AH=CurVideoMode
  356.   push dx                                                    ;Register retten.
  357.   push di
  358.   push es
  359.   test bh,1
  360.   GetPageArrayIndex 0,di                   ;Welche von beiden Pages meint der?
  361.   mov  dx,[CursPosTable+di]                           ;Entsprechende CursorPos
  362.   mov  es,cs:[PageSegment+di]                          ;und PageSegment holen.
  363.   cld
  364.   cmp  ah,8
  365.   je   ReadGraphChar                 ;GraphMode? Dann andere Routine benutzen.
  366.   DisplayAdress_Text dl,dh                                       ;CursorPos in
  367.   shl  ax,1                                                 ;Adresse umrechnen
  368.   mov  di,ax
  369.   mov  ax,es:[di]                       ; => dort steht das Attr und der Char.
  370.   jmp  SHORT ReadCharDone                         ;Das war's eigentlich schon,
  371. ReadGraphChar:                       ;im GraphMode ist das viel komplizierter:
  372.   push cx
  373.   shl  dh,1                  ;Cursor YPos von "CharLines" nach "Scans" wandeln
  374.   DisplayAdress_Graph dl,dh          ;und in eine Adresse umrechnen, die dann,
  375.   mov  di,cs:[DispStartTable+di]                    ;zum DispStart addiert und
  376.   add  di,ax                                        ;auf eine BitMap begrenzt,
  377.   and  di,1FFFh                                ;auf das Graphik-Pattern zeigt.
  378.   mov  ah,0FFh                                 ;XOR-Flag auf "revers" setzen.
  379. SearchAgain:
  380.   mov  al,es:[di]                   ;Das erste Byte des Graphik-Patterns holen
  381.   xor  al,ah                                 ;und mit dem XOR-Flag verknüpfen.
  382.   mov  si,OFFSET ZeichenSatz8x8
  383.   mov  cx,256
  384.   sub  si,8                            ;Dieses erste Byte nacheinander mit dem
  385. CompFirstByte:                            ;jeweils ersten Byte der 256 Zeichen
  386.   add  si,8                                         ;(komplette ASCII-Tabelle)
  387.   cmp  al,cs:[si]                              ;des ZeichenSatzes vergleichen.
  388.   loopne CompFirstByte
  389.   jne  UnknownChar
  390.   push si                                       ;Weitertesten und die gesamten
  391.   push di                                             ;8 Bytes Graphik-Pattern
  392.   mov  dl,2                                     ;(gleich 2 Scans) vergleichen.
  393. CompRestOfChar:
  394.   lods byte ptr cs:[si]              ;Nächstes Byte aus dem ZeichenSatz holen,
  395.   xor  al,ah                                     ;über das XOR-Flag verknüpfen
  396.   cmp  al,es:[di]              ;und mit dem nächsten Graphik-Byte vergleichen.
  397.   jne  CharCompared
  398.   add  di,2000h             ;Gleich? Dann eine Zeile tiefer (= nächste BitMap)
  399.   jno  CompRestOfChar                  ;es sei denn, das war schon die letzte.
  400.   add  di,90                  ;In diesem Fall Zeiger einen Scan tiefer setzen.
  401.   and  di,1FFFh                                      ;Dabei PageWrap beachten.
  402.   dec  dl                                             ;War das der letze Scan?
  403.   jnz  CompRestOfChar                          ;Nicht? Dann weitervergleichen.
  404. CharCompared:
  405.   pop  di
  406.   pop  si                                                  ;Vergleich beendet.
  407.   je   GraphCharRecognized              ;Wie sah denn das Ergebnis aus, gleich
  408.   mov  al,es:[di]                                              ;oder ungleich?
  409.   xor  al,ah
  410.   test cx,cx              ;Ungleich? Dann wieder nach erstem Byte suchen, aber
  411.   jnz  CompFirstByte       ;nur wenn Zeichensatz noch nicht zuende durchsucht.
  412. UnknownChar:
  413.   inc  ah         ;Zeichen nicht erkannt? Dann nochmal mit neuem XOR-Flag pro-
  414.   jz   SearchAgain   ;bieren, wenn es nicht schon alle Werte angenommen hatte.
  415. GraphCharRecognized:
  416.   mov  al,255
  417.   sub  al,cl
  418.   pop  cx
  419.   mov  ah,07h
  420.   test dl,dl                   ;Zeichen gefunden. Wie stand denn das XOR-Flag?
  421.   jz   ReadCharDone                                              ;Auf reverse?
  422.   mov  ah,70h                      ;Dann entsprechendes Attribute zurückgeben.
  423. ReadCharDone:  ;AL = Char,  AH = Attribute.
  424.   pop  es
  425.   pop  di                                                ;Register zurückholen
  426.   pop  dx
  427.   pop  si                                      ;und ReturnAdresse kurz lupfen.
  428.   add  sp,2        ;Dann kann ich nämlich den gepushten AX vom Stack entfernen
  429.   push ax                           ;und statt dessen den neuen dorthin legen.
  430.   push si                               ;Jetzt nur noch die alte ReturnAdresse
  431.   ret                                      ;wieder zurück und wir sind fertig.
  432. ReadAttrChar ENDP  ;AX and SI destroyed.
  433.  
  434. WriteCharOnly PROC NEAR
  435.   ;BH=PageNr, CX=NrOfChars, AL=CharToWrite, AH=CurVideoMode
  436.   cmp  ah,8                 ;Ist Graphik-Mode aktiv? Im GraphMode ist es nicht
  437.   mov  bl,7             ;möglich, NUR ein Zeichen OHNE Attribute zu schreiben.
  438.   je   WriteAttrChar        ;Statt dessen "WriteAttrChar" mit Attr=7 benutzen.
  439.   push cx                               ;Also TextModus. Dann Register retten.
  440.   push dx
  441.   push di
  442.   push es
  443.   jcxz WriteCharDone               ;Gar nichts zum Schreiben da? Dann Abbruch.
  444.   cld
  445.   push ax                                      ;CharToWrite zwischenspeichern.
  446.   test bh,1                                                 ;Welche Page denn?
  447.   GetPageArrayIndex 0,di                                       ;Ach so, DIE...
  448.   mov  dx,[CursPosTable+di]
  449.   mov  es,cs:[PageSegment+di]
  450.   DisplayAdress_Text dl,dh                    ;CursorPos in Adresse umrechnen,
  451.   shl  ax,1                                         ;nach "ByteOffset" wandeln
  452.   mov  di,ax                                      ;ergibt  ES:DI = CharAdress.
  453.   pop  ax
  454. WriteCharOnlyLoop:                              ;Zeichen ins VideoRam donnern:
  455.   stosb                                              ;Character-Byte schreiben
  456.   inc  di                                   ;aber Attribute-Byte überspringen.
  457.   loop WriteCharOnlyLoop                                     ;Noch Zeichen da?
  458. WriteCharDone:
  459.   pop  es
  460.   pop  di
  461.   pop  dx
  462.   pop  cx
  463.   ret
  464. WriteCharOnly ENDP  ;AX and SI destroyed.
  465.  
  466. WriteAttrChar PROC NEAR
  467.   ;BH=PageNr, CX=NrOfChars, AL=Char, BL=Attribute, AH=CurVideoMode
  468.   push cx
  469.   push dx                                                     ;Register retten
  470.   push di
  471.   push es
  472.   jcxz WriteCharDone                    ;Ist überhaupt etwas da zum Schreiben?
  473.   cld
  474.   test bh,1
  475.   GetPageArrayIndex 0,di                      ;Um welche Page handelt es sich?
  476.   mov  dx,[CursPosTable+di]                        ;Entsprechende "CursorPos"
  477.   mov  es,cs:[PageSegment+di]                        ;und "PageSegment" holen.
  478.   cmp  ah,8                                        ;Sind wir im Graphik-Modus?
  479.   je   WriteGraphChar                           ;Dann andere Routine benutzen.
  480.   push ax                                      ;CharToWrite zwischenspeichern.
  481.   DisplayAdress_Text dl,dh                    ;CursorPos in Adresse umrechnen,
  482.   shl  ax,1                                         ;nach "ByteOffset" wandeln
  483.   mov  di,ax                                      ;ergibt  ES:DI = CharAdress.
  484.   pop  ax
  485.   mov  ah,bl
  486.   rep  stosw                                     ;Zeichen ins VideoRam donnern
  487.   jmp  SHORT WriteCharDone                                        ;und fertig.
  488. WriteGraphChar:
  489.   push bx                       ;Im Graphik-Mode ist alles viel komplizierter:
  490.   push ax                                      ;CharToWrite zwischenspeichern.
  491.   shl  dh,1                           ;DH von "CharLines" nach "Scans" wandeln
  492.   DisplayAdress_Graph dl,dh                 ;und daraus die Adresse berechnen,
  493.   mov  di,cs:[DispStartTable+di]                       ;außerdem den DispStart
  494.   add  di,ax                                                  ;nicht vergessen
  495.   and  di,1FFFh                                                ;und begrenzen.
  496.   mov  dh,0                                                      ;AND-Flag und
  497.   mov  bh,0                                                 ;XOR-Flag löschen.
  498.   test bl,70h                             ;Soll das Zeichen revers erscheinen?
  499.   jz   NotReverse
  500.   dec  bh                              ;Dann XOR-Flag setzen. Soll das Zeichen
  501.   test bl,07h                   ;revers & white (=> weiß auf weiß) erscheinen?
  502.   jnz  GotFlags                   ;Dann stimmt das mit dem gelöschte AND-Flag.
  503. SetAndFlag:
  504.   dec  dh                                              ;Sonst AND-Flag setzen,
  505.   jmp  SHORT GotFlags                                 ;dann stimmen die Flags.
  506. NotReverse:
  507.   test bl,07h             ;Soll das Zeichen black & non revers (=> schwarz auf
  508.   jnz  SetAndFlag        ;schwarz) erscheinen? Dann auch erst AND-Flag setzen.
  509. GotFlags:
  510.   mov  si,OFFSET ZeichenSatz8x8
  511.   pop  ax
  512.   mov  ah,0                       ;ASCII-Code des Zeichens auf 16Bit erweitern
  513.   shl  ax,1                                        ;und 3x nach links schieben
  514.   shl  ax,1                                                   ;(entspricht *8)
  515.   shl  ax,1                                                 ;ergibt den Offset
  516.   add  si,ax                                      ;in die ZeichenSatz-Tabelle.
  517.   mov  bl,2                               ;2 komplette Scans (gleich 8 Zeilen)
  518.   mov  dl,cl                       ;zu je CL Zeichen (gleich Bytes) schreiben.
  519.   mov  ax,es
  520. WriteNextLineOfChars:
  521.   mov  es,ax
  522.   ComputeWrapPos di
  523.   push di                                    ;ZeilenAnfang für später merken.
  524.   lods byte ptr cs:[si]             ;So: Eine Zeile aus dem ZeichenSatz holen,
  525.   and  al,dh                                         ;mit den Flags verknüpfen
  526.   xor  al,bh                                            ;und soweit schreiben,
  527.   rep  stosb                                    ;wie ohne 8k-Wrap möglich ist.
  528.   xor  di,di                      ;Dann Zeiger auf den PageAnfang zurücksetzen
  529.   mov  cl,ah                                     ;und auch den Rest schreiben.
  530.   rep  stosb
  531.   pop  di
  532.   mov  ax,es                               ;Jetzt ES auf nächste BitMap setzen
  533.   add  ah,02h                                 ;(=eine Bildschirmzeile tiefer).
  534.   cmp  ah,HIGH(Page0Seg)+8
  535.   je   PrepareNextScan
  536.   cmp  ah,HIGH(Page1Seg)+8
  537.   jb   WriteNextLineOfChars                   ;War das etwa die letzte BitMap?
  538. PrepareNextScan:
  539.   sub  ah,08h                  ;Dann Zeiger wieder auf die erste BitMap setzen
  540.   add  di,90                                          ;aber einen Scan tiefer.
  541.   and  di,1FFFh
  542.   dec  bl                                                 ;War das der letzte?
  543.   jnz  WriteNextLineOfChars                         ;Nicht? Dann weitermachen.
  544.   pop  bx
  545.   pop  es
  546.   pop  di
  547.   pop  dx
  548.   pop  cx
  549.   ret
  550. WriteAttrChar ENDP  ;AX and SI destroyed.
  551.  
  552. WriteDot PROC NEAR  ;CX=XPos, DX=YPos, AL=ColorNr, AH=CurVideoMode
  553.   push bx
  554.   push cx                                                    ;Register retten.
  555.   push dx
  556.   push es
  557.   cmp  ah,8                          ;Sind wir auch wirklich im Graphik-Modus?
  558.   jne  WriteDotDone             ;Im TextModus gibt es keine Punkte zum Setzen.
  559.   push ax                                                   ;ColorByte merken.
  560.   test ActivePage,1
  561.   call ComputeDotAdress                                   ;Adresse des Punktes
  562.   mov  al,80h                                                 ;und seine Maske
  563.   shr  al,cl                                                       ;berechnen.
  564.   mov  ah,al
  565.   xor  ah,0FFh                              ;Byte invertieren als Lösch-Maske.
  566.   pop  dx                                               ;ColorByte zurückholen
  567.   test dl,7Fh                                                     ;und testen:
  568.   jnz  MakeDotWhite                               ;Soll der Punkt schwarz oder
  569.   mov  al,0                                                      ;weiß werden?
  570. MakeDotWhite:
  571.   test dl,dl                              ;Soll der Punkt entsprechend gesetzt
  572.   js   InvertDot                                      ;oder invertiert werden?
  573.   and  es:[bx],ah                     ;Punkt erst mal löschen (schwarz setzen)
  574.   or   es:[bx],al                          ;und dann bei Bedarf wieder setzen,
  575.   jmp  SHORT WriteDotDone                                          ;das war's.
  576. InvertDot:                                                 ;Punkt invertieren?
  577.   xor  es:[bx],al                         ;Dann Byte mit der Maske verknüpfen.
  578. WriteDotDone:
  579.   pop  es
  580.   pop  dx
  581.   pop  cx
  582.   pop  bx
  583.   ret
  584. WriteDot ENDP  ;AX destroyed.
  585.  
  586. ReadDot PROC NEAR  ;CX=XPos, DX=YPos.
  587.   push bx
  588.   push cx
  589.   push dx
  590.   push es
  591.   test ActivePage,1                             ;Welche Page ist gerade aktiv?
  592.   call ComputeDotAdress
  593.   mov  al,80h                                            ;Maske aus der Nummer
  594.   shr  al,cl                                              ;des Bits bestimmen.
  595.   test es:[bx],al                                       ;Ist das Bit gelöscht?
  596.   mov  al,0                                        ;Dann "black" zurückmelden,
  597.   jz   DotIsBlack
  598.   mov  al,7                                                    ;sonst "white".
  599. DotIsBlack:
  600.   pop  es
  601.   pop  dx
  602.   pop  cx                                               ;Register wieder holen
  603.   pop  bx
  604.   pop  si                                      ;und ReturnAdresse kurz lupfen.
  605.   add  sp,2        ;Dann kann ich nämlich den gepushten AX vom Stack entfernen
  606.   push ax                           ;und statt dessen den neuen dorthin legen.
  607.   push si                               ;Jetzt nur noch die alte ReturnAdresse
  608.   ret                                      ;wieder zurück und wir sind fertig.
  609. ReadDot ENDP  ;AX and SI destroyed.
  610.  
  611. TeletypeOut PROC NEAR
  612.   ;AL=CharToWrite, BL=ForegroundColor in GraphMode, AH=CurVideoMode
  613.   push bx
  614.   mov  bh,ActivePage
  615.   cmp  ah,8                             ;In welchem VideoMode sind wir gerade?
  616.   je   GraphTeletype
  617.   mov  bl,al                   ;TextMode? Dann zu schreibendes Zeichen merken,
  618.   call ReadAttrChar                      ;Zeichen+Attribute an CursorPos holen
  619.   mov  al,bl                                     ;und das neue Zeichen mit dem
  620.   mov  bl,ah                                   ;Attribute des alten schreiben.
  621. GraphTeletype:
  622.   test bh,1                                  ;In welcher Page sind wir gerade?
  623.   GetPageArrayIndex OFFSET(CursPosTable),si
  624.   call WriteOneChar         ;So, jetzt das Zeichen MITSAMT Attribute schreiben
  625.   call UpdateCursorPos               ;und neue CursorPos an den 6845 schicken.
  626.   pop  bx
  627.   ret
  628. TeletypeOut ENDP  ;AX and SI destroyed.
  629.  
  630. GetVideoState PROC NEAR
  631.   mov  bh,ActivePage
  632.   pop  ax                            ;ReturnAdresse kurz lupfen. Dann kann ich
  633.   add  sp,2                      ;nämlich den gepushten AX vom Stack entfernen
  634.   push word ptr CurVideoMode   ;und statt dessen den neuen Wert dorthin legen.
  635.   push ax                               ;Jetzt nur noch die alte ReturnAdresse
  636.   ret                                      ;wieder zurück und wir sind fertig.
  637. GetVideoState ENDP  ;AX destroyed, BH=ActivePage.
  638.  
  639. WriteString PROC NEAR
  640.   ;[ES:BP]=String, CX=NrOfChars, DX=CursStartPos, BH=PageNr, AL=SubModeNr
  641.   ;AH=CurVideoMode, BL=Attribute in some SubModes.
  642.   push bp
  643.   test al,1                             ;Wie sieht das LSB der SubMode-Nr aus?
  644.   pushf                                            ;Zustand für später merken!
  645.   test bh,1                                        ;In welcher Page schreiben?
  646.   GetPageArrayIndex OFFSET(CursPosTable),si
  647.   push [si]                                    ;Entsprechende CursorPos merken
  648.   mov  [si],dx                ;und StartPos des Strings als CursPos speichern.
  649.   jcxz EndOfString
  650.   and  al,2                                 ;SubMode 0 oder 1? Dann enthält BL
  651.   jz   CommonAttribute                 ;das Attribute für den gesamten String.
  652.   push bx
  653. IndividualAttributes:     ;Sonst besteht der String aus Zeichen UND Attibutes:
  654.   mov  ax,es:[bp]                 ;Davon die erste Char-Attr-Kombination lesen
  655.   inc  bp                           ;und Zeiger vorerst ein Byte weitersetzen.
  656.   cmp  al,7
  657.   je   NotPrintable
  658.   cmp  al,8                                                  ;Jetzt mal sehen:
  659.   je   NotPrintable
  660.   cmp  al,10                                        ;Ist das Zeichen weder BEL
  661.   je   NotPrintable
  662.   cmp  al,13                                         ;noch BS noch CR noch LF?
  663.   je   NotPrintable     ;Dann ist das ein printable Char mit einem Attrib-Byte
  664.   inc  bp            ;dahinter, der Zeiger muß entsprechend korrigiert werden.
  665. NotPrintable:
  666.   mov  bl,ah
  667.   call WriteOneChar                                  ;mit Attr in BL schreiben
  668.   loop IndividualAttributes                                       ;und weiter.
  669.   pop  bx
  670.   jmp  SHORT EndOfString
  671. CommonAttribute:
  672.   mov  al,es:[bp]                            ;Erstes Zeichen des Strings lesen
  673.   call WriteOneChar                                ;und mit BL=Attr schreiben.
  674.   inc  bp                                                   ;Zeiger weiter und
  675.   loop CommonAttribute                                     ;nochmal von Vorne.
  676. EndOfString:
  677.   pop  ax                       ;Alte CursorPos VOR dem Schreiben zurückholen,
  678.   popf                                                     ;dann Flags testen:
  679.   pop  bp
  680.   jz   DontMoveCursor             ;Sollte der Cursor bewegt werden oder nicht?
  681.   mov  ax,[si]                       ;Ja? Dann neue Position an 6845 schicken.
  682. DontMoveCursor:
  683.   mov  [si],ax                           ;Sonst alte Position wieder speichern
  684.   jmp  UpdateCursorPos                                  ;und an 6845 schicken.
  685. WriteString ENDP  ;AX and SI destroyed.
  686.  
  687. NotImplemented PROC NEAR
  688.   pop  ax                   ;RückkehrAdresse nach "NewInt10Handler" verwerfen,
  689.   pop  ax
  690.   pop  ds                                     ;gerettete Register wiederholen,
  691.   mov  ss,cs:SavedInt10Stack+2
  692.   mov  sp,cs:SavedInt10Stack               ;auf alten Stack zurückschalten und
  693.   mov  cs:Int10Active,False               ;entsprechendes Flag wieder löschen,
  694.   pop  si                                                   ;dann in den alten
  695.   jmp  dword ptr cs:[SavedInt10Vec]                   ;Int10-Handler springen.
  696. NotImplemented ENDP
  697.  
  698. SetVideoMode PROC NEAR  ;AL=ModeNr
  699.   cli                                  ;Interrupts erst mal wieder verhindern!
  700.   cmp  al,7                                      ;Soll Modus 7 gesetzt werden?
  701.   je   HerkGrafAus                                           ;Machen wir doch.
  702.   cmp  al,8
  703.   jne  NotImplemented                          ;Weder 7 noch 8? Ha'm wa' nich.
  704.   push dx                                                ;Also Modus 8 setzen?
  705.   mov  CurVideoMode,al                      ;"VideoMode" im BiosSeg speichern.
  706.   mov  dx,8000h
  707.   mov  al,HGC_Full
  708.   mov  ah,00101011b   ;1st Page, Blinker enable, Display enable, Hires
  709.   mov  si,OFFSET GraphModeTiming
  710.   jmp  SHORT UpdateVideoMode
  711. HerkGrafAus:
  712.   push dx                                                ;Also Modus 7 setzen?
  713.   mov  CurVideoMode,al                      ;"VideoMode" im BiosSeg speichern.
  714.   mov  dx,1000h
  715.   mov  al,HGC_Text
  716.   mov  ah,00101001b   ;1st Page, Blinker enable, Display enable, Text
  717.   mov  si,OFFSET TextModeTiming
  718. UpdateVideoMode:
  719.   ;[CS:SI]=Timing-Daten, AH=ModeReg-Inhalt, AL=Configuration, DX=BytesPerPage
  720.   mov  BytesPerPage,dx
  721.   mov  dx,ConfigReg
  722.   out  dx,al                                            ;Configuration setzen.
  723.   mov  dx,StatusReg
  724. NotYetSync:
  725.   in   al,dx
  726.   test al,80h
  727.   jnz  NotYetSync                               ;Auf Vertical Retrace warten.
  728.   mov  dx,ModeReg
  729.   mov  al,ah
  730.   out  dx,al                                          ;Video-Modus umschalten,
  731.   mov  ModeRegCont,al                ;Inhalt des ModeReg im BiosSegment merken
  732.   mov  ah,0
  733.   mov  dx,IndexReg                              ;und die Timing-Daten in einer
  734. OutStringByteLoop:                             ;Schleife in den Chip schieben.
  735.   mov  al,ah
  736.   out  dx,al                                  ;Zuerst die Nummer des Registers
  737.   inc  dx                                                       ;ins IndexReg,
  738.   lods byte ptr cs:[si]                    ;dann das nächste Timing-Byte holen
  739.   out  dx,al                                       ;und ins DataReg schreiben.
  740.   dec  dx
  741.   inc  ah
  742.   cmp  ah,14
  743.   jne  OutStringByteLoop                           ;Noch weitere Timing-Daten?
  744.   xor  ax,ax
  745.   mov  CursPosTable+0,ax                                    ;Cursor nach (0/0)
  746.   mov  CursPosTable+2,ax                                     ;in Page 0 und 1,
  747.   mov  cs:DispStartTable+0,ax                                        ;außerdem
  748.   mov  cs:DispStartTable+2,ax                       ;"DispStart" zurücksetzen.
  749.   call SelActivePage                    ;Page 0 selektieren und vor dem langen
  750.   sti                                  ;Bildschirm-Löschen Interrupts enablen.
  751.   mov  dx,256*25+80                                 ;Bildschirm enthält 80x25,
  752.   cmp  CurVideoMode,8
  753.   jne  SmallScreen
  754.   mov  dx,256*NrOfLines+NrOfChars             ;im Graphik-Modus 90x45 Zeichen.
  755. SmallScreen:
  756.   mov  byte ptr NrOfColumns+1,0
  757.   mov  byte ptr NrOfColumns,dl                        ;Noch ein paar Variablen
  758.   dec  dh
  759.   mov  LastTextLine,dh                                ;im Bios-Segment setzen.
  760.   inc  dh
  761.   push bx
  762.   push cx
  763.   mov  bh,0                                              ;Bildschirm in Page 0
  764.   mov  bl,7                                                   ;mit Attribute 7
  765.   mov  cx,0
  766.   call ClearWindow                                                   ;löschen,
  767.   inc  bh                                                   ;ebenso in Page 1.
  768.   mov  cx,0
  769.   mov  dl,byte ptr NrOfColumns
  770.   mov  dh,LastTextLine
  771.   inc  dh
  772.   call ClearWindow
  773.   mov  cx,0C0Dh
  774.   call SetCursorShape
  775.   pop  cx
  776.   pop  bx
  777.   pop  dx
  778.   ret
  779. SetVideoMode ENDP  ;AX and SI destroyed.
  780.  
  781. NewInt5Handler PROC FAR
  782.   push ax                                                    ;Register retten.
  783.   push ds
  784.   cmp  cs:PrtScrActive,True          ;Wird gerade schon eine HardCopy gemacht?
  785.   je   PrtScrAborted                                    ;Dann diese abbrechen,
  786.   mov  ax,BiosData
  787.   mov  ds,ax                                     ;sonst DS auf das BiosSegment
  788.   mov  ah,CurVideoMode                  ;setzen und von dort VideoModus lesen.
  789.   cmp  ah,7
  790.   je   SupportedMode                                ;Sind wir im Herc-TextMode
  791.   cmp  ah,8                                           ;oder im Herc-GraphMode?
  792.   je   SupportedMode                                    ;Dann geht das uns an,
  793.   pop  ds                                            ;im anderen Fall Register
  794.   pop  ax                                            ;wieder herstellen und an
  795.   jmp  dword ptr cs:[SavedInt5Vec]            ;alten PrtScr-Handler übergeben.
  796. SupportedMode:
  797.   mov  cs:PrtScrActive,True                          ;Jetzt geht's gleich los.
  798.   cmp  ah,7                                   ;In welchem VideoModus sind wir?
  799.   mov  cs:SavedInt5Stack,sp
  800.   mov  cs:SavedInt5Stack+2,ss
  801.   mov  ax,cs                             ;Entsprechendes Flag schon mal setzen
  802.   mov  ss,ax                                 ;und auf eigenen Stack umschalten
  803.   mov  sp,OFFSET MyInt5Stack+StackSize       ;(SP auf das ENDE des Bereichs!).
  804.   mov  al,ActivePage
  805.   sti                        ;Dann kann ich jetzt auch die Interrupts enablen.
  806.   je   MakeTextHardcopy
  807.   call PrintGraphScreen                              ;TextModus? Dann Drucken.
  808.   jmp  SHORT PrtScrDone
  809. MakeTextHardcopy:
  810.   call PrintTextScreen        ;GraphModus? Dann andere Druck-Routine benutzen.
  811. PrtScrDone:
  812.   mov  ss,cs:SavedInt5Stack+2
  813.   mov  sp,cs:SavedInt5Stack                    ;Auf alten Stack zurückschalten
  814. PrtScrAborted:
  815.   mov  cs:PrtScrActive,False
  816.   pop  ds
  817.   pop  ax                                           ;und Register wiederholen.
  818.   iret
  819. NewInt5Handler ENDP
  820.  
  821. IF Debugging
  822. ;----------------------------------------------------------------------------+
  823. BreakPoint PROC NEAR                                                        ;!
  824.   pushf                                                                     ;!
  825.   push ax                                                                   ;!
  826.   push dx                                                                   ;!
  827.   push si                                                                   ;!
  828.   mov  dx,ModeReg                                                           ;!
  829.   mov  al,00101001b                                                         ;!
  830.   out  dx,al                                 ;Video-Modus umschalten,       ;!
  831.   mov  si,OFFSET TextModeTiming                                             ;!
  832.   mov  ah,0                                                                 ;!
  833.   mov  dx,IndexReg                     ;und die Timing-Daten in einer       ;!
  834.   cld                                                                       ;!
  835. OutStringLoop0:                       ;Schleife in den Chip schieben.       ;!
  836.   mov  al,ah                                                                ;!
  837.   out  dx,al                         ;Zuerst die Nummer des Registers       ;!
  838.   inc  dx                                              ;ins IndexReg,       ;!
  839.   lods byte ptr cs:[si]           ;dann das nächste Timing-Byte holen       ;!
  840.   out  dx,al                              ;und ins DataReg schreiben.       ;!
  841.   dec  dx                                                                   ;!
  842.   inc  ah                                                                   ;!
  843.   cmp  ah,14                                                                ;!
  844.   jne  OutStringLoop0                     ;Noch weitere Timing-Daten?       ;!
  845.   pop  si                                                                   ;!
  846.   pop  dx                                                                   ;!
  847.   pop  ax                                                                   ;!
  848.   popf                                                                      ;!
  849.   int  3                                                                    ;!
  850.   pushf                                                                     ;!
  851.   push ax                                                                   ;!
  852.   push dx                                                                   ;!
  853.   push si                                                                   ;!
  854.   mov  dx,ModeReg                                                           ;!
  855.   mov  al,00101011b                                                         ;!
  856.   out  dx,al                                                                ;!
  857.   mov  si,OFFSET GraphModeTiming                                            ;!
  858.   mov  ah,0                                                                 ;!
  859.   mov  dx,IndexReg                     ;und die Timing-Daten in einer       ;!
  860.   cld                                                                       ;!
  861. OutStringLoop1:                       ;Schleife in den Chip schieben.       ;!
  862.   mov  al,ah                                                                ;!
  863.   out  dx,al                         ;Zuerst die Nummer des Registers       ;!
  864.   inc  dx                                              ;ins IndexReg,       ;!
  865.   lods byte ptr cs:[si]           ;dann das nächste Timing-Byte holen       ;!
  866.   out  dx,al                              ;und ins DataReg schreiben.       ;!
  867.   dec  dx                                                                   ;!
  868.   inc  ah                                                                   ;!
  869.   cmp  ah,14                                                                ;!
  870.   jne  OutStringLoop1                     ;Noch weitere Timing-Daten?       ;!
  871.   pop  si                                                                   ;!
  872.   pop  dx                                                                   ;!
  873.   pop  ax                                                                   ;!
  874.   popf                                                                      ;!
  875.   ret                                                                       ;!
  876. BreakPoint ENDP                                                             ;!
  877.                                                                             ;!
  878. MarkOn PROC NEAR                                                            ;!
  879.   push es                                                                   ;!
  880.   push ax                                                                   ;!
  881.   mov  al,23h                                                               ;!
  882.   out  61h,al                                                               ;!
  883.   mov  ax,0B000h                                                            ;!
  884.   mov  es,ax                                                                ;!
  885.   pop  ax                                                                   ;!
  886.   mov  byte ptr es:[159],7                                                  ;!
  887.   inc  byte ptr es:[158]                                                    ;!
  888.   pop  es                                                                   ;!
  889.   ret                                                                       ;!
  890. MarkOn ENDP                                                                 ;!
  891.                                                                             ;!
  892. MarkOff PROC NEAR                                                           ;!
  893.   push es                                                                   ;!
  894.   push ax                                                                   ;!
  895.   mov  al,20h                                                               ;!
  896.   out  61h,al                                                               ;!
  897.   mov  ax,0B000h                                                            ;!
  898.   mov  es,ax                                                                ;!
  899.   pop  ax                                                                   ;!
  900.   mov  byte ptr es:[159],7                                                  ;!
  901.   dec  byte ptr es:[158]                                                    ;!
  902.   pop  es                                                                   ;!
  903.   ret                                                                       ;!
  904. MarkOff ENDP                                                                ;!
  905. ;----------------------------------------------------------------------------+
  906. ENDIF
  907.  
  908. ;+---------------------------------------------------------------------------+
  909. ;!     Der Teil ab hier wird nach dem Installieren wieder freigegeben.       !
  910. ;+---------------------------------------------------------------------------+
  911. ASSUME CS:TheProgram,DS:TheProgram,ES:TheProgram,SS:TheProgram
  912.  
  913. RotateBuffer  LABEL BYTE
  914. MyInt10Stack  EQU RotateBuffer+BufSize
  915. MyInt5Stack   EQU MyInt10Stack+StackSize
  916. EndOfProgram  EQU MyInt5Stack+StackSize
  917. Card_Unknown  EQU 0
  918. Card_Mono     EQU 1
  919. Card_Herkules EQU 2
  920. VideoCard     DB ?
  921. VideoMode     DB ?
  922. ExplainFlag   DB LOW False
  923. WhenTimeOut   DW ?,?
  924.  
  925. Main PROC NEAR
  926.   call CheckHardware
  927.   mov  VideoCard,al
  928.   mov  VideoMode,ah
  929.   mov  si,80h                ;Ab [PSP:80h] befinden sich die Aufruf-Parameter.
  930.   call ProcessCommandLine
  931.   cmp  ExplainFlag,True                   ;Sollen nur Infos ausgegeben werden?
  932.   je   GetInfos
  933.   jmp  Initialisation
  934. Main ENDP                                             ;Dann Fall-Through nach:
  935.  
  936. GetInfos PROC NEAR
  937.   mov  dx,OFFSET ExplainMsg                      ;Erklärungs-Message ausgeben.
  938.   mov  ah,9  ;FunctionCall PRINT STRING             ;Sie endet mit den Worten:
  939.   int  21h                                            ;"Checking Hardware:"...
  940.   mov  ah,Ret_Expl
  941.   mov  al,VideoCard
  942.   cmp  al,Card_Unknown
  943.   mov  dx,OFFSET UnknownMsg                           ;Mal sehen: Was für eine
  944.   je   MessageAndStop                                 ;Graphik-Karte haben wir
  945.   cmp  al,Card_Mono                                                ;hier denn?
  946.   mov  dx,OFFSET MonoCardMsg
  947.   je   MessageAndStop
  948.   mov  ah,9  ;FunctionCall PRINT STRING                   ;Eine Herkules? Dann
  949.   mov  dx,OFFSET HerkCardMsg                               ;testen wir weiter:
  950.   int  21h
  951.   call TestIfResident                                     ;Ist dieses Programm
  952.   mov  ah,Ret_Expl                                            ;schon resident?
  953.   mov  dx,OFFSET NotResiMsg
  954.   jne  MessageAndStop                                       ;Nein, noch nicht.
  955.   mov  dx,OFFSET ResidentMsg
  956.   mov  ah,9  ;FunctionCall PRINT STRING
  957.   int  21h
  958.   mov  ah,Ret_Expl
  959.   mov  dx,OFFSET OnMsg
  960.   cmp  es:FastScrollFlag,True
  961.   je   MessageAndStop
  962.   mov  dx,OFFSET OffMsg
  963. GetInfos ENDP                                      ;Schon wieder Fall-Through:
  964.  
  965. MessageAndStop PROC NEAR   ;[DS:DX]=Message, AH=ReturnCode.
  966.   push ax
  967.   mov  ah,9  ;FunctionCall PRINT STRING
  968.   int  21h
  969.   pop  ax
  970.   mov  al,ah
  971.   mov  ah,4Ch  ;FunctionCall TERMINATE PROCESS
  972.   int  21h
  973. MessageAndStop ENDP
  974.  
  975. RemoveFromMemory PROC NEAR  ;[DX:0]=RotateBuffer, [ES:0]=residentes HERKULES.
  976.   cmp  VideoMode,8                            ;Sind wir z.Z. im Graphik-Modus?
  977.   jne  LegalVidMode
  978.   mov  ah,0
  979.   mov  al,7                     ;Dann auf jeden Fall in den Text-Modus zurück-
  980.   int  10h                      ;schalten, sonst stehen wir nacher im Dunkeln.
  981. LegalVidMode:
  982.   mov  ah,5                                            ;Das tun wir auch, wenn
  983.   mov  al,0                                           ;jetzt gerade die zweite
  984.   int  10h                                                    ;Page aktiv ist.
  985.   mov  ah,25h  ;FunctionCall SET VECTOR
  986.   lds  dx,dword ptr es:SavedInt5Vec                      ;Int5 (PrtScr)-Vektor
  987.   mov  al,5h                                           ;auf alten Bios-Treiber
  988.   int  21h                                                      ;zurückbiegen,
  989.   mov  ah,25h  ;FunctionCall SET VECTOR
  990.   lds  dx,dword ptr es:SavedInt10Vec                     ;ebenso Int10-Vektor.
  991.   mov  al,10h
  992.   int  21h
  993.   mov  dx,ConfigReg                      ;Ach ja, man sollte die Konfiguration
  994.   mov  al,HGC_Diag                        ;auch noch auf "DIAG" stellen, damit
  995.   out  dx,al                             ;die Karte wieder MGA-kompatibel ist.
  996.   nop
  997.   push es:[2Ch]                      ;Adresse des Environment-Segments merken.
  998.   mov  ah,49h  ;FunctionCall FREE MEMORY              ;Speicher des residenten
  999.   int  21h                                               ;HERKULES' freigeben.
  1000.   pop  es
  1001.   mov  ah,49h  ;FunctionCall FREE MEMORY            ;Speicher des Environment-
  1002.   int  21h                                                ;Segments freigeben.
  1003.   mov  ah,35h  ;FunctionCall GET VECTOR
  1004.   mov  al,1Fh
  1005.   int  21h                                         ;Wohin zeigt der Vektor $1F
  1006.   cmp  bx,OFFSET ZeichenSatz8x8              ;(der Zeiger auf die obere Hälfte
  1007.   jne  GrafTablNotLoaded                          ;des IBM-ASCII-Zeichensatzes
  1008.   mov  ax,es                                            ;für CGA-GraphikModi)?
  1009.   mov  dx,cs
  1010.   cmp  ax,dx                             ;Auf unseren eingebauten ZeichenSatz?
  1011.   jne  GrafTablNotLoaded
  1012.   xor  dx,dx                                               ;Dann diesen Vektor
  1013.   mov  ds,dx                                            ;auf NIL zurücksetzen,
  1014.   mov  ah,25  ;FunctionCall SET VECTOR             ;sonst gibt der nacher noch
  1015.   mov  al,1Fh                                ;Zeichen aus dem ZeichenSatz aus,
  1016.   int  21h                                ;der schon gar nicht mehr existiert.
  1017. GrafTablNotLoaded:
  1018.   mov  ah,Ret_Ok
  1019.   mov  dx,cs
  1020.   mov  ds,dx
  1021.   mov  dx,OFFSET RemovedMsg
  1022.   jmp  MessageAndStop
  1023. RemoveFromMemory ENDP
  1024.  
  1025. Initialisation PROC NEAR   ;Neuen Video-Treiber installieren.
  1026.   call TestIfResident
  1027.   je   AlreadyResident                                        ;Schon resident?
  1028.   mov  al,VideoCard                   ;Noch nicht! Dann sollten wir eigentlich
  1029.   cmp  al,Card_Herkules                  ;resident werden, aber zuerst testen:
  1030.   mov  dx,OFFSET InvCardMsg                      ;Ist das eine Herkules-Karte?
  1031.   je   MakeResident                                     ;Dann ist es ja prima.
  1032.   jmp  FatalError                             ;NICHT? Um Gotteswillen, Fehler!
  1033. AlreadyResident:
  1034.   mov  al,FastScrollFlag
  1035.   cmp  al,Dunnow                 ;Wurde eine der FastScroll-Options angegeben?
  1036.   je   RemoveFromMemory          ;Nicht? Dann Treiber aus dem Speicher werfen.
  1037.   cmp  es:FastScrollFlag,TRUE                  ;Ist FastScrolling momentan an?
  1038.   mov  es:FastScrollFlag,al
  1039.   jne  UpdateDone
  1040.   cmp  al,False                ;Und soll es jetzt ausgeschaltet werden ("/S")?
  1041.   jne  UpdateDone
  1042.   mov  al,VideoMode
  1043.   cmp  al,8                      ;Und sind wir außerdem noch im Graphik-Modus?
  1044.   jne  UpdateDone
  1045.   mov  ah,00h  ;SET VIDEO MODE                  ;Dann muß vorher der DispStart
  1046.   int  10h                                       ;wieder auf 0 gesetzt werden.
  1047. UpdateDone:
  1048.   mov  si,OFFSET PrnInfo
  1049.   mov  di,si
  1050.   mov  cx,PrnInfoSize                          ;(Eventuell neue) Drucker-Daten
  1051.   cld                                               ;von hier in das residente
  1052.   rep  movsb                                             ;Programm übertragen.
  1053.   mov  ah,Ret_Ok
  1054.   mov  dx,OFFSET UpdatedMsg
  1055.   jmp  MessageAndStop
  1056. Initialisation ENDP
  1057.  
  1058. MakeResident PROC NEAR
  1059.   cmp  FastScrollFlag,Dunnow                     ;Keine Angaben zu FastScroll?
  1060.   jne  FlagIsSet
  1061.   mov  FastScrollFlag,FALSE                     ;Dann Default=FALSE verwenden.
  1062. FlagIsSet:
  1063.   mov  dx,OFFSET EndOfProgram
  1064.   cmp  ds:[6],dx                                ;Genug Platz für RotateBuffer?
  1065.   mov  dx,OFFSET OutOfMemMsg
  1066.   jb   FatalError                                        ;Nicht? Dann Abbruch.
  1067.   mov  ah,25h  ;FunctionCall SET VECTOR
  1068.   mov  al,5h
  1069.   mov  dx,OFFSET NewInt5Handler                              ;INT 5 auf dieses
  1070.   int  21h                                                 ;Programm umlenken,
  1071.   mov  ah,25h  ;FunctionCall SET VECTOR
  1072.   mov  al,10h                                                 ;genauso INT 10.
  1073.   mov  dx,OFFSET NewInt10Handler
  1074.   int  21h
  1075.   mov  dx,ConfigReg                   ;Da dieser INT10-Handler auch die zweite
  1076.   mov  al,HGC_Text                          ;VideoPage unterstützt, wird diese
  1077.   out  dx,al                             ;jetzt in der Herkules-Karte enabled.
  1078.   push ds
  1079.   mov  ax,BiosData
  1080.   mov  ds,ax                    ;Außerdem wird die Nummer der letzten Zeile im
  1081.   ASSUME DS:BiosData           ;BiosData-Segment auf 24 gesetzt, das alte Bios
  1082.   mov  LastTextLine,24         ;unterstützt diese Variable nämlich noch nicht.
  1083.   mov  bl,7
  1084.   mov  bh,1
  1085.   mov  cx,0                                ;Jetzt sollten wir noch die zweite,
  1086.   mov  dx,25*256+80           ;bis jetzt ja weder benutzte noch initialisierte
  1087.   call ClearWindow                                              ;Page löschen.
  1088.   pop  ds
  1089.   ASSUME DS:TheProgram
  1090.   mov  ah,35h  ;FunctionCall GET VECTOR
  1091.   mov  al,1Fh                                   ;Vektor $1F zeigt im auf einen
  1092.   int  21h                                     ;ZeichenSatz mit den oberen 128
  1093.   cmp  bx,0                                    ;IBM-ASCII-Zeichen für die CGA-
  1094.   jne  GrafTablAlreadyLoaded                  ;Graph-Modi. Ist dieser Zeichen-
  1095.   mov  ax,es                                      ;Satz schon geladen, ist der
  1096.   cmp  ax,0                                              ;Zeiger ungleich NIL?
  1097.   jne  GrafTablAlreadyLoaded
  1098.   mov  ah,25h  ;FunctionCall SET VECTOR   ;Dann Zeiger auf eigenen ZeichenSatz
  1099.   mov  al,1Fh                                 ;setzen, das bringt zwar nur mit
  1100.   mov  dx,OFFSET ZeichenSatz8x8+128*8       ;einem CGA-Simulator etwas, kostet
  1101.   int  21h                           ;aber keinen Speicherplatz und deshalb...
  1102. GrafTablAlreadyLoaded:
  1103.   mov  ah,9  ;FunctionCall PRINT STRING
  1104.   mov  dx,OFFSET HerkCardMsg
  1105.   int  21h                                                 ;Dann entsprechende
  1106.   mov  dx,OFFSET SuccessMsg                                 ;Message ausgeben,
  1107.   int  21h
  1108.   mov  ah,31h  ;FunctionCall KEEP PROCESS
  1109.   mov  al,Ret_Ok
  1110.   mov  dx,OFFSET EndOfProgram+15
  1111.   mov  cl,4
  1112.   shr  dx,cl
  1113.   cld
  1114.   int  21h                                               ;und resident werden.
  1115. MakeResident ENDP
  1116.  
  1117. FatalError PROC NEAR  ;[DS:DX]=ErrorMessage.
  1118.   push dx
  1119.   mov  dx,OFFSET FatalErrMsg
  1120.   mov  ah,9  ;FunctionCall PRINT STRING
  1121.   int  21h
  1122.   pop  dx
  1123.   mov  ah,Ret_Error
  1124.   jmp  MessageAndStop
  1125. FatalError ENDP
  1126.  
  1127. ProcessCommandLine PROC NEAR   ;[DS:SI]=CommandLine
  1128.   cld
  1129.   lodsb                                                     ;Längen-Byte lesen
  1130.   mov  cl,al
  1131.   mov  ch,0                                                ;und nach CX holen.
  1132. ParameterLoop:
  1133.   jcxz EoCommandLine                       ;CX=0 => Ende der CmdLine erreicht.
  1134.   lodsb                                                        ;Zeichen holen,
  1135.   dec  cx
  1136.   cmp  al,' '
  1137.   je   ParameterLoop
  1138.   cmp  al,'?'                                               ;ein Fragezeichen?
  1139.   jne  OtherParam
  1140.   mov  ExplainFlag,True                                      ;Dann Flag setzen
  1141.   jmp  SHORT ParameterLoop                 ;und nächsten Parameter bearbeiten.
  1142. OtherParam:
  1143.   cmp  al,OptChar                                             ;Ist es ein "/"?
  1144.   mov  dx,OFFSET InvParamMsg
  1145.   jne  FatalError                                      ;Auch nicht? => Fehler.
  1146.   mov  dx,OFFSET InvOptionMsg                  ;CommandLine hinter "/" zuende?
  1147.   jcxz FatalError                                      ;=> Invalid Option.
  1148.   lodsb
  1149.   dec  cx                                            ;Zeichen hinter "/" holen
  1150.   cmp  al,'a'
  1151.   jb   IsUpcase
  1152.   cmp  al,'z'                                   ;und nach Großschrift wandeln.
  1153.   ja   IsUpcase
  1154.   sub  al,'a'-'A'
  1155. IsUpcase:
  1156.   cmp  al,'F'                                                 ;Ist es ein "F"?
  1157.   mov  ah,True                            ;Dann Flag setzen für "Fast Scroll".
  1158.   je   SetScrollFlag
  1159.   cmp  al,'S'
  1160.   mov  ah,False                        ;Ist es ein "S"? Dann das Flag löschen.
  1161.   je   SetScrollFlag
  1162.   jmp  FatalError                      ;Weder "F" noch "S"? => Invalid Option.
  1163. SetScrollFlag:
  1164.   mov  FastScrollFlag,ah
  1165.   jmp  SHORT ParameterLoop
  1166. EoCommandLine:
  1167.   ret
  1168. ProcessCommandLine ENDP
  1169.  
  1170. CheckHardware PROC NEAR
  1171.   mov  ah,0Fh  ;Get Video Mode
  1172.   int  10h                               ;Was für ein Video-Mode ist das denn?
  1173.   push ax
  1174.   mov  ah,Card_Unknown
  1175.   cmp  al,7                      ;VideoMode 7 oder 8? Dann könnte das durchaus
  1176.   je   PossiblyHerkulesCard                ;eine Herkules Karte sein, muß aber
  1177.   cmp  al,8                                     ;noch genauer getestet werden.
  1178.   jne  CheckingDone                      ;Weder 7 noch 8? => Unbekannte Karte.
  1179. PossiblyHerkulesCard:             ;Es KÖNNTE also eine sein, muß näher testen:
  1180.   mov  dx,BiosData
  1181.   mov  es,dx                             ;Port-Adresse der Video-Karte mit der
  1182.   ASSUME ES:BiosData
  1183.   cmp  es:VidCtrlIoAdr,IndexReg             ;der Herkules und MDA vergleichen:
  1184.   ASSUME ES:NOTHING
  1185.   jne  CheckingDone                          ;Ungleich? Dann unbekannte Karte.
  1186.   mov  ah,0  ;Read Ticker-Count
  1187.   int  1Ah                         ;Uhrzeit in 1/18-Sekunden nach CX:DX holen,
  1188.   add  dx,9                                   ;9/18 = ½ Sekunde dazu addieren.
  1189.   adc  cx,0
  1190.   mov  WhenTimeOut,dx
  1191.   mov  WhenTimeOut+2,cx
  1192. WaitLoop:
  1193.   mov  cx,10000                                        ;10000 mal nacheinander
  1194.   mov  dx,StatusReg                                       ;das Status-Register
  1195.   in   al,dx                                                        ;auslesen:
  1196.   and  al,80h
  1197.   mov  ah,al
  1198. CloseLoop:                                                  ;Wenn sich das MSB
  1199.   in   al,dx                                             ;(Horizontal Retrace)
  1200.   and  al,80h                                                         ;ändert,
  1201.   cmp  al,ah
  1202.   loope CloseLoop
  1203.   mov  ah,Card_Herkules
  1204.   jne  CheckingDone                         ;dann ist das eine Herkules-Karte.
  1205.   mov  ah,0  ;Read Ticker-Count
  1206.   int  1Ah                                                     ;Zeit abfragen:
  1207.   cmp  cx,WhenTimeOut+2                             ;Ist die ½ Sekunde vorbei?
  1208.   jb   WaitLoop                               ;Noch nicht? Dann weiter warten.
  1209.   mov  ah,Card_Mono
  1210.   ja   CheckingDone           ;Schon vorbei? Dann ist das wohl keine Herkules.
  1211.   cmp  dx,WhenTimeOut
  1212.   jb   WaitLoop
  1213. CheckingDone:
  1214.   mov  al,ah
  1215.   pop  dx
  1216.   mov  ah,dl
  1217.   ret
  1218. CheckHardware ENDP  ;AL=Karten-Kennung, AH=VideoMode.
  1219.  
  1220. TestIfResident PROC NEAR                             ;Sind wir schon resident?
  1221.   mov  ah,35h  ;FunctionCall GET VECTOR
  1222.   mov  al,5h
  1223.   int  21h
  1224.   mov  SavedInt5Vec,bx                             ;Vektor für INT 5  (PrtScr)
  1225.   mov  SavedInt5Vec+2,es                         ;nach ES:BX holen und merken.
  1226.   mov  ah,35h  ;FunctionCall GET VECTOR
  1227.   mov  al,10h                                              ;Vektor für INT 10h
  1228.   int  21h                                                   ;nach ES:BX holen
  1229.   mov  SavedInt10Vec,bx                                           ;und merken.
  1230.   mov  SavedInt10Vec+2,es                    ;Stimmt der Ofs des INT10-Vektors
  1231.   cmp  bx,OFFSET NewInt10Handler          ;mit dem des INT10-Handlers überein?
  1232.   jne  NotResident                  ;Nicht? Dann sind wir noch nicht resident.
  1233.   cmp  SavedInt5Vec,OFFSET NewInt5Handler                ;Genauso die Ofs beim
  1234.   jne  NotResident                                        ;INT5 vergleichen...
  1235.   mov  ax,SavedInt10Vec+2                             ;Und die Segs vom INT 5-
  1236.   cmp  ax,SavedInt5Vec+2                                  ;und INT 10-Handler?
  1237.   jne  NotResident
  1238.   mov  si,OFFSET NewInt10Handler+1       ;Um ganz sicher zu gehen, vergleichen
  1239.   mov  di,si                               ;wir auch noch die Version-Strings.
  1240.   mov  cx,17
  1241.   cld
  1242.   rep  cmpsb                                           ;Stimmen beide überein?
  1243. NotResident:
  1244.   ret
  1245. TestIfResident ENDP  ;ZF=1 wenn schon resident. ES = SEG(residenterHandler).
  1246.  
  1247. UnknownMsg   DB '*** Unknown Graphics Card ***',13,10,'$'
  1248. MonoCardMsg  DB '*** IBM Monochrome Card detected ***',13,10,'$'
  1249. HerkCardMsg  DB '*** HGC detected, HERKULES $'
  1250. SuccessMsg   DB 'made resident ***',13,10,'$'
  1251. NotResiMsg   DB 'not yet resident ***',13,10,'$'
  1252. ResidentMsg  DB 'already loaded with FastScrolling $'
  1253. OnMsg        DB 'ON ***',13,10,'$'
  1254. OffMsg       DB 'OFF ***',13,10,'$'
  1255. UpdatedMsg   DB '*** HERKULES already resident, Options updated ***',13,10,'$'
  1256. RemovedMsg   DB '*** HERKULES removed from Memory ***',13,10,'$'
  1257. FatalErrMsg  DB '*** Fatal Error: $'
  1258. InvCardMsg   DB 'This is no Herkules Card ***',13,10,'$'
  1259. InvParamMsg  DB 'Invalid Parameter ***',13,10,'$'
  1260. InvOptionMsg DB 'Invalid Option ***',13,10,'$'
  1261. OutOfMemMsg  DB 'Out of Memory ***',13,10,'$'
  1262. ExplainMsg   DB 'This Program is an extension to the INT 10h',13,10
  1263.              DB 'for support of the Herkules Graphic Card in',13,10
  1264.              DB 'Hires-Mode (720x360). It does NOT work with',13,10
  1265.              DB 'the IBM Monochrome Card! By adding the Opt-',13,10
  1266.              DB 'ions  "/F" or "/S", you may specify whether',13,10
  1267.              DB 'Fast-  or Slow-Scrolling is to be used. For',13,10
  1268.              DB 'FastScroll the DisplayStart-Register of the',13,10
  1269.              DB '6845 will be changed, which might interfere',13,10
  1270.              DB 'to some Programs.        Checking Hardware:',13,10,'$'
  1271. ;-----------------------------------------------------------------------------
  1272. TheProgram ENDS
  1273. END EntryPoint
  1274.